package com.ghery.ftp.client;

import com.ghery.ftp.config.FtpConfiguration;
import com.ghery.ftp.strategy.FtpFilterStrategy;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileFilter;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @author ghery
 * @date 2020/8/6
 */
@Component
public class FtpClient {

	private static Logger log = LoggerFactory.getLogger(FtpClient.class);

	public static final String FOLDER_SPLIT = "/";

    @Autowired
    private FtpConfiguration ftpConfiguration;

	/**
	 * ftp 读取文件时的过滤列表
	 */
	@Autowired
    private List<FtpFilterStrategy> ftpFilterStrategys;


	/**
	 * ftp写入文件数据
	 * @param folderName
	 * @param fileName
	 * @param data
	 * @return
	 */
	public boolean writeFile(String folderName,String fileName,byte[] data) {
		long startTime = System.currentTimeMillis();
		FTPClient ftpClient = getFtpClient();
		boolean isDebug = log.isDebugEnabled();
		try{
			if(ftpClient == null){
				return false;
			}
			if(!StringUtils.isEmpty(folderName)) {
				changeFtpWorkDir(folderName, ftpClient);
			}
			InputStream picStream = new ByteArrayInputStream(data);
			boolean isSuccess = ftpClient.storeFile(fileName, picStream);
			if(!isSuccess){
				log.error("上传FTP服务器失败，文件为:{},目录:{}",fileName,folderName);
			}
			picStream.close();
			return isSuccess;
		} catch (IOException e) {
			log.error("file  upload  to FTP exception : {}",e);
			return false ;
		} finally {
			disconnect(ftpClient);
			if(isDebug){
				log.debug("FTP 写文件操作耗时：{} ms",System.currentTimeMillis() - startTime);
			}
		}
	}

	/**
	 * 删除文件
	 * @param folderName
	 * @param fileName
	 * @return
	 */
	public boolean deleteFile(String folderName,String fileName) {
		FTPClient ftpClient = getFtpClient();
		try{
			if(!StringUtils.isEmpty(folderName)) {
				changeFtpWorkDir(folderName, ftpClient);
			}
			return ftpClient.deleteFile(fileName);
		} catch (Exception e) {
			log.error("ftp delete file failed!!!");
			return false ;
		} finally {
			disconnect(ftpClient);
		}
	}

	/**
	 * 重命名文件，在相同的目录下
	 * @param folderName
	 * @param srcName
	 * @param destName
	 * @return
	 */
	public boolean renameFile(String folderName,String srcName,String destName) {
		FTPClient ftpClient = getFtpClient();
		try{
			if(!StringUtils.isEmpty(folderName)) {
				changeFtpWorkDir(folderName, ftpClient);
			}
			return ftpClient.rename(srcName,destName);
		} catch (Exception e) {
			log.error("ftp rename file failed!!!");
			return false ;
		} finally {
			disconnect(ftpClient);
		}
	}

	/**
	 * 读取文件
	 * @param folderName
	 * @param ftpFilterStrategy
	 * @return
	 */
	public Map<String,byte[]>  readFile(String folderName,FtpFilterStrategy ftpFilterStrategy) {
		FTPClient ftpClient = getFtpClient();
        try {
			if(!StringUtils.isEmpty(folderName)) {
				changeFtpWorkDir(folderName, ftpClient);
			}
			if(ftpFilterStrategys == null){
				ftpFilterStrategys = new ArrayList<>();
			}
			if(ftpFilterStrategy != null){
				ftpFilterStrategys.add(0,ftpFilterStrategy);
			}
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpClient.printWorkingDirectory(), new FTPFileFilter() {
                @Override
                public boolean accept(FTPFile file) {
					/**
					 * 自定义ftp过滤规则
					 */
                    if(ftpFilterStrategys != null){
                    	for(FtpFilterStrategy ftpFilterStrategy:ftpFilterStrategys){
							if(!ftpFilterStrategy.accept(file)){
								return false;
							}
						}
                    }
                    return  true;
                }
            });

            log.info("目录：{},文件数：{}",folderName,ftpFiles.length);
			if(ftpFiles==null || ftpFiles.length<=0){
				return null;
			}
			int size = ftpFiles.length < ftpConfiguration.getEveryReceiveNum() ? ftpFiles.length : ftpConfiguration.getEveryReceiveNum();
			//转list后按文件名称排序
			List<FTPFile> fileList = new ArrayList<>(Arrays.asList(ftpFiles));
			fileList.sort(Comparator.comparing(FTPFile::getName));
			
			Map<String,byte[]> result = new ConcurrentHashMap<String,byte[]>();
			for (int i = 0; i < size ; i++) {
				byte[] retBuff = getFileByte(ftpClient,fileList.get(i).getName());
			    if(retBuff==null || retBuff.length==0){
                    log.info("get ftp file length is 0 ...");
                    continue;
                }
				result.put(ftpFiles[i].getName(),retBuff);
			}
			return result;
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		} finally {
			disconnect(ftpClient);
		}
		return null;
	}

	private byte[] getFileByte(FTPClient ftpClient ,String fileName) {
		InputStream inStream = null ;
		byte[] imgdata = null ;
		try{
			inStream = ftpClient.retrieveFileStream(fileName);
			if(inStream == null){
				return null ;
			}
			ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
			byte[] buff = new byte[1024*1024];
			int rc;
			while((rc = inStream.read(buff)) > 0){
				swapStream.write(buff ,0 ,rc);
			}
			imgdata = swapStream.toByteArray();
			swapStream.flush();
			swapStream.close();
			return imgdata;
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return null ;
		}finally {
			if(inStream != null){
				try {
					inStream.close();
					ftpClient.completePendingCommand();
				} catch (IOException e) {
					log.error(e.getMessage(),e);
				}
			}
		}
	}

	/**
	 * 根据策略列出所有文件
	 * @param folderName
	 * @param ftpFilterStrategy
	 * @return
	 */
	public List<FTPFile> listFileByStrategy(String folderName,FtpFilterStrategy ftpFilterStrategy) {
		FTPClient ftpClient = getFtpClient();
		try {
			if(!StringUtils.isEmpty(folderName)) {
				changeFtpWorkDir(folderName, ftpClient);
			}
			FTPFile[] ftpFiles = ftpClient.listFiles(ftpClient.printWorkingDirectory(), new FTPFileFilter() {
				@Override
				public boolean accept(FTPFile file) {
					if(ftpFilterStrategy.accept(file)){
						return true;
					}
					return  false;
				}
			});
			log.info("目录：{},文件数：{}",folderName,ftpFiles.length);
			if(ftpFiles == null || ftpFiles.length <= 0){
				return null;
			}
			//转list后按文件名称排序
			List<FTPFile> fileList = new ArrayList<>(Arrays.asList(ftpFiles));
			return fileList;
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		} finally {
			disconnect(ftpClient);
		}
		return null;
	}


	/**
	 * 获取FTP连接客户端
	 * @return 获取到ftp连接后，不要更改连接的属性
	 */
	private FTPClient getFtpClient() {
		long startTime = System.currentTimeMillis();
		GenericObjectPool<FTPClient> ftpPool = FtpClientPool.getFTPPool(ftpConfiguration);
		FTPClient ftpClient = null;
		try {
			ftpClient = ftpPool.borrowObject();
			long endTime = System.currentTimeMillis();
			if(log.isDebugEnabled()){
				log.debug("获取FTP连接耗时：{} ms",endTime - startTime);
			}
			return ftpClient;
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			ftpPool.returnObject(ftpClient);
			return null ;
		}
	}

	/**
	 * 根据FTP配置，切换工作目录
	 * @param folderName
	 * @param ftpClient
	 * @throws IOException
	 */
	private void changeFtpWorkDir(String folderName, FTPClient ftpClient) throws IOException {
		String pathName = ftpConfiguration.getHomeDir() + FOLDER_SPLIT + folderName;
		if (!ftpClient.changeWorkingDirectory(pathName)) {
			ftpClient.makeDirectory(pathName);
			ftpClient.changeWorkingDirectory(pathName);
		}
	}

	/**
	 * 释放FTP连接
	 * @param ftp
	 */
	private void disconnect(FTPClient ftp) {
		if(ftp == null){
			return;
		}
		try {
			GenericObjectPool<FTPClient> ftpPool = FtpClientPool.getFTPPool(ftpConfiguration);
			ftp.changeWorkingDirectory(ftpConfiguration.getHomeDir());
			ftpPool.returnObject(ftp);
		}catch (Exception e){
			log.error(e.getMessage(),e);
		}
	}

}
